/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.florent37.github.com.expansionpanel;


import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ScrollView;
import ohos.agp.render.Canvas;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * lipeiquan
 *
 * @since 2021-05-06
 */
public class ExpansionLayout extends ScrollView {


    private final List<IndicatorListener> indicatorListeners = new ArrayList<>();
    private final List<Listener> listeners = new ArrayList<>();
    public Boolean singleListener = false;
    private boolean expanded = false;
    private AnimatorValue animator;
    private DrawTask task;
    private int nHeight = 0;


    public ExpansionLayout(Context context) {
        super(context);
        startDrawTask();
    }

    public ExpansionLayout(Context context, AttrSet attrSet) {
        super(context, attrSet);
        startDrawTask();
    }

    public ExpansionLayout(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    public void init(int height) {
        nHeight = height;
        setHeight(0);
    }


    public void startDrawTask() {
        if (task == null) {
            task = new DrawTask() {
                @Override
                public void onDraw(Component component, Canvas canvas) {
                    if (!expanded) {
                        setHeight(0);
                    } else {
                        setHeight(nHeight == 0 ? getComponentAt(0).getHeight() : nHeight);
                    }
                }
            };
        }
        addDrawTask(task);
    }


    public boolean isExpanded() {
        return expanded;
    }

    public interface Listener {
        void onExpansionChanged(ExpansionLayout expansionLayout, boolean expanded);
    }

    public interface IndicatorListener {
        void onStartedExpand(ExpansionLayout expansionLayout, boolean willExpand);
    }

    public void addListener(Listener listener) {
        if (singleListener) {
            listeners.clear();
            listeners.add(listener);
        } else if (listener != null && !listeners.contains(listener)) {
            listeners.add(listener);
        }
    }

    public void removeListener(Listener listener) {
        if (listener != null) {
            listeners.remove(listener);
        }
    }

    public void addIndicatorListener(IndicatorListener listener) {
        if (listener != null && !indicatorListeners.contains(listener))
            indicatorListeners.add(listener);
    }

    public void removeIndicatorListener(IndicatorListener listener) {
        if (listener != null) {
            indicatorListeners.remove(listener);
        }
    }

    public void toggle(boolean animate) {
        toggle(animate, true);
    }

    public void toggle(boolean animated, boolean notify) {
        if (expanded) {
            collapse(animated, notify);
        } else {
            expand(animated, notify);
        }
    }

    public void collapse(boolean animated) {
        collapse(animated, true);
    }

    public void collapse(boolean animated, final boolean ping) {
        if (!isEnabled() || !expanded) {
            return;
        }
        if (ping) {
            pingIndicatorListeners(false);
        }
        if (animated) {
            if (animator != null) {
                animator.stop();
                animator.cancel();
            }
            animator = new AnimatorValue();
            animator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float value) {
                    int height = (int)((1 - value) * (nHeight == 0 ? getComponentAt(0).getHeight() : nHeight));
                    setHeight(height);
                    startDrawTask();

                }
            });
            animator.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator animator) {

                }

                @Override
                public void onStop(Animator animator) {

                }

                @Override
                public void onCancel(Animator animator) {

                }

                @Override
                public void onEnd(Animator animator) {

                    ExpansionLayout.this.animator = null;
                    if (ping) {
                        pingListeners();
                    }
                }

                @Override
                public void onPause(Animator animator) {

                }

                @Override
                public void onResume(Animator animator) {

                }
            });
            expanded = false;
            animator.start();


        } else {
            setHeight(0);
            expanded = false;
            if (ping) {
                pingListeners();
            }
        }
    }

    private void pingIndicatorListeners(boolean willBeExpanded) {

        for (IndicatorListener indicatorListener : indicatorListeners) {
            if (indicatorListener != null) {
                indicatorListener.onStartedExpand(this, willBeExpanded);
            }
        }
    }


    public void expand(boolean animated) {
        expand(animated, true);
    }

    public void expand(boolean animated, final boolean ping) {

        if (!isEnabled() || expanded) {
            return;
        }

        if (ping) {
            pingIndicatorListeners(true);
        }
        if (animated) {

            if (animator != null && animator.isRunning()) {
                return;
            }
            animator = new AnimatorValue();
            animator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float value) {

                    int height = (int) (value * (nHeight == 0 ? getComponentAt(0).getHeight() : nHeight));
                    setHeight(height);
                    startDrawTask();
                }
            });
            animator.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator animator) {

                }

                @Override
                public void onStop(Animator animator) {

                }

                @Override
                public void onCancel(Animator animator) {

                }

                @Override
                public void onEnd(Animator animator) {

                    ExpansionLayout.this.animator = null;
                    if (ping) {
                        pingListeners();
                    }
                }

                @Override
                public void onPause(Animator animator) {

                }

                @Override
                public void onResume(Animator animator) {

                }
            });
            expanded = true;
            animator.start();
        } else {
            setHeight(getComponentAt(0).getHeight());
            expanded = true;
            if (ping) {
                pingListeners();
            }
        }
    }


    private void pingListeners() {
        for (Listener listener : listeners) {
            if (listener != null) {
                listener.onExpansionChanged(this, expanded);
            }
        }
    }


}
